#include "trans_file_server.h"
#include "../timeoutManager/timeoutManager.h"

/* Usage:  */
int put_file_to_serv(tlv_msg_t cmd_msg, user_session_t *user_session)
{
    // 拿value里面的文件名
    char filename[4096] = {0};
    memcpy(filename, cmd_msg.value, cmd_msg.hdr.length);

    tlv_msg_t recv_pack;
    bzero(&recv_pack, sizeof(recv_pack));
    // 接收客户端文件的md5值
    int netfd = user_session->netfd;
    bzero(&recv_pack, sizeof(recv_pack));
    ssize_t recv_sret;
    recv_sret = tlv_recv(netfd, &recv_pack);
    printf("puts接收到的客户端md5:%s\n", recv_pack.value);
    if (recv_sret == 1)
    {
        printf("客户端下线\n");
        return 1;
    }
    char md5_value_of_putsfile[33] = {0};
    memcpy(md5_value_of_putsfile, recv_pack.value, recv_pack.hdr.length);
    // 判断文件夹下是否有对应的文件，传入传出的数组用于记录文件夹下对应文件的md5值
    char md5_value_record[33] = {0};
    int if_file_exist = CheckFileExist(user_session, filename, md5_value_record);
    printf("文件夹下的现有文件md5值为:%s\n", md5_value_record);
    if (if_file_exist == -1)
    {
        printf("getsfile文件查询，数据库操作失败\n");
        return -1;
    }
    //------------------------------------------------------------
    if (if_file_exist == 1)
    {
        // 比较文件哈希值是否相同
        int if_md5_equal = strcmp(md5_value_of_putsfile, md5_value_record);
        // md5值相同，秒传
        if (if_md5_equal == 0)
        {
            // 目录下有同名文件存在
            printf("上传文件/同名/同哈希/秒传\n");
            int put_ret = putsfile_no_wait(netfd);
            if (put_ret == 1)
            {
                return 1;
            }
        }
        // md5值不相同，直传，数据库表项覆盖
        else
        {
            // 检查磁盘目录中是否有对应的文件
            if (access(md5_value_of_putsfile, F_OK) == 0)
            {
                // 有对应文件，秒传，覆盖
                printf("上传文件/同名/不同哈希/秒传\n");
                int inser_ret = MYSQL_Data_Replace(user_session, filename, md5_value_of_putsfile);
                if (inser_ret == -1)
                {
                    printf("上传文件/同名/覆盖/秒传/数据库操作失败");
                    return -1;
                }
                // 有对应的文件秒传，覆盖
                int put_ret = putsfile_no_wait(netfd);
                if (put_ret == 1)
                {
                    return 1;
                }
            }
            else
            {
                // 没有对应文件，直传，覆盖
                printf("上传文件/同名/不同哈希/直传\n");
                int put_ret = putfile_real_trans(netfd, md5_value_of_putsfile);
                if (put_ret == 1)
                {
                    return 1;
                }
                // 对现有的数据库的表格内容中的哈希值进行覆盖
                int inser_ret = MYSQL_Data_Replace(user_session, filename, md5_value_of_putsfile);
                if (inser_ret == -1)
                {
                    printf("上传文件/同名/覆盖/直传/数据库操作失败");
                    return -1;
                }
                put_ret = puts_file_finish_feedback(netfd);
                if (put_ret == 1)
                {
                    return 1;
                }
            }
        }
    }
    else if (if_file_exist == 0)
    {
        // 没有文件存在，access查磁盘是否有文件存在
        if (access(md5_value_of_putsfile, F_OK) == 0)
        {
            // 插入新的文件表项
            printf("上传文件/无文件/插入/秒传\n");
            int inser_ret = MYSQL_Data_Insert(user_session, filename, md5_value_of_putsfile);
            if (inser_ret == -1)
            {
                printf("上传文件/无文件/插入/秒传/数据库操作失败");
                return -1;
            }
            // 磁盘有对应文件，秒传，插入数据库表项
            int put_ret = putsfile_no_wait(netfd);
            if (put_ret == 1)
            {
                return 1;
            }
        }
        else
        {
            // 磁盘没有对应文件，直传，插入数据库表项
            printf("上传文件/无文件/插入/直传\n");
            int put_ret = putfile_real_trans(netfd, md5_value_of_putsfile);
            if (put_ret == 1)
            {
                return 1;
            }
            // 插入新的文件表项
            int inser_ret = MYSQL_Data_Insert(user_session, filename, md5_value_of_putsfile);
            if (inser_ret == -1)
            {
                printf("上传文件/无文件/插入/直传/数据库操作失败");
                return -1;
            }
            put_ret = puts_file_finish_feedback(netfd);
            if (put_ret == 1)
            {
                return 1;
            }
        }
    }
    //------------------------------------------------------------
    return 0;
}

int putsfile_no_wait(int netfd)
{
    // 传回是秒传输还是直传，让客户端有对应的操作
    tlv_msg_t send_pack;
    bzero(&send_pack, sizeof(send_pack));
    char *send_pack_msg = "exist";
    send_pack.hdr.type = PUTS_FILE_EXIST;
    send_pack.hdr.length = strlen(send_pack_msg);
    memcpy(send_pack.value, send_pack_msg, strlen(send_pack_msg));
    ssize_t send_sret = tlv_send(netfd, &send_pack);
    printf("秒传\n");
    if (send_sret == 1)
    {
        printf("传输过程中用户崩溃断线，清理下载资源\n");
        return 1;
    }
    return 0;
}
int putfile_real_trans(int netfd, char *md5_value_of_putsfile)
{
    // 传回是秒传输还是直传，让客户端有对应的操作
    tlv_msg_t send_pack;
    bzero(&send_pack, sizeof(send_pack));
    char *send_pack_msg = "noexist";
    send_pack.hdr.type = PUTS_FILE_NOEXIST;
    send_pack.hdr.length = strlen(send_pack_msg);
    memcpy(send_pack.value, send_pack_msg, strlen(send_pack_msg));
    ssize_t send_sret = tlv_send(netfd, &send_pack);
    printf("直传\n");
    if (send_sret == 1)
    {
        printf("传输过程中用户崩溃断线，清理下载资源\n");
        return 1;
    }
    tlv_msg_t recv_pack;
    bzero(&recv_pack, sizeof(recv_pack));
    // 接收文件长度
    ssize_t recv_sret = tlv_recv(netfd, &recv_pack);
    if (recv_sret == 1)
    {
        printf("客户端下线\n");
        return 1;
    }
    off_t file_length;
    memcpy(&file_length, recv_pack.value, sizeof(file_length));
    printf("%ld\n", file_length);
    // 打开文件描述符，用哈希值命名文件
    int fd = open(md5_value_of_putsfile, O_RDWR | O_CREAT, 0666);
    // 现有的文件长度
    off_t current_file_length = 0;
    // 接收数据包
    while (current_file_length < file_length)
    {
        bzero(&recv_pack, sizeof(recv_pack));
        // printf("开始上传文件\n");
        // 每一轮接收的小火车
        recv_sret = tlv_recv(netfd, &recv_pack);
        if (recv_sret == 1)
        {
            printf("传输过程中用户崩溃断线，清理下载资源\n");
            close(fd);
            unlink(md5_value_of_putsfile);
            return 1;
        }
        timeout_manager_tick(&g_timeout_manager); // 更新超时管理器，表示用户仍然活跃
        // 错误检查
        if (recv_pack.hdr.length != 4096)
        {
            printf("%d\n", recv_pack.hdr.length);
        }

        ssize_t wriret = write(fd, recv_pack.value, recv_pack.hdr.length);
        if (wriret == -1)
        {
            printf("文件写入失败\n");
        }
        // printf("下载成功一轮\n");
        current_file_length += recv_pack.hdr.length;
    }
    close(fd);
    printf("现已成功上传文件，断连时也保存文件\n");
    return 0;
}

int puts_file_finish_feedback(int netfd)
{

    tlv_msg_t recv_pack;
    tlv_msg_t send_pack;
    bzero(&recv_pack, sizeof(recv_pack));
    ssize_t recv_sret = tlv_recv(netfd, &recv_pack);
    if (recv_sret == 1)
    {
        printf("客户端下线\n");
        return 1;
    }
    printf("%s,上传成功\n", recv_pack.value);

    bzero(&send_pack, sizeof(send_pack));
    char *send_pack_msg_end = "上传成功";
    send_pack.hdr.type = DATA_END;
    send_pack.hdr.length = strlen(send_pack_msg_end);
    memcpy(send_pack.value, send_pack_msg_end, strlen(send_pack_msg_end));
    ssize_t send_sret = tlv_send(netfd, &send_pack);
    if (send_sret == 1)
    {
        printf("客户端下线\n");
        return 1;
    }
    return 0;
}
